sed入门
sed 是一个比较古老的,功能十分强大的用于文本处理的流编辑器,加上正则表达式的支持,可以进行大量的复杂的文本编辑操作。
简介
sed 全名为 stream editor,是一个流编辑器,用于处理来自文件或管道的输入流,进行基本文本的匹配及处理。
sed会一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,成为"模式空间",接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。
sed能够对来自于管道的文本进行过滤,与其他类型编辑器相比,这是它的独特之处。
使用
使用形式:sed OPTIONS . . . [SCRIPT] [INPUTFILE . . .]
:
- OPTIONS:命令行选项
- [SCRIPT]:操作脚本
- [INPUTFILE . . .] :输入流来源
Linux命令行执行一条命令后一般会返回一个状态码(echo $?
),sed返回的状态码有:
- 0:成功完成
- 1:命令无效、语法无效、正则表达式无效或者在”--posix“下执行了GNU sed扩展的命令。
- 2:命令行上指定的一个或者多个输入文件不能打开(例如,文件找不到,或者无权限读取,被拒绝),程序会继续处理其他文件。
- 4:出现一个I/O错误,或运行时发生严重的操作错误,GNU sed立即中止程序。
操作脚本中的行操作命令
a 命令——添加新行
在匹配的行下面添加新行
i 命令——插入新行
在匹配的行上面插入新行
c 命令——行替换
替换指定范围的行的内容
d 命令——删除
删除指定范围
p 命令——打印
打印指定范围的内容
= 命令——打印行号
打印指定范围的行号
s 命令——正则替换
指定范围内容进行正则替换,格式为:
s/正则表达式/要替换的内容/
s 命令最后跟个 g 表示替换该行所有匹配
不加 g 的 s 只能替换每一行匹配到的第一个
sed '4,8s/\(line\)\([[:digit:]]\+\)/\2 - \1/' a.txt # 4,8 表示从第 4 行到第 8 行 # \(line\)\([[:digit:]]\+\) 是正则表达式 # \1 表示正则表达式中第一个括号匹配的结果 # \2 表示正则表达式中第二个括号匹配的结果 # 可以加 -r 参数开启扩展正则表达式,写成等价形式 sed -r '4,8s/(line)([[:digit:]]+)/\2 - \1/' a.txt
y 命令——字符映射替换
r 命令——行替换,替换内容为文件内容
操作脚本中的其它命令
{} ——脚本块
在大括号内用分号隔开命令,可以实现执行多个命令,多个命令范围相同,则可以省略相同匹配后面的范围指定
脚本块可以嵌套,嵌套时范围指定不同,则会取交集
b ——标签跳转
跳转到用冒号开头表示的标签,当标签在最后时,可以省略,而且当 b 命令指定的标签不存在时,会自动跳转到最后
如果标签在前可能造成死循环,需要注意指定行
t ——条件正则跳转
如果前一条命令执行成功,则跳转到用冒号开头表示的标签
空间交换命令
**模式空间:**sed 命令默认是一行一行处理的,每读取到一行,会放到模式空间里,然后执行脚本来处理模式空间的内容,处理完后会清空模式空间,并且读取下一行继续处理,如此循环直到行尾。模式空间相当于专门用于 sed 处理的字符串缓冲区。
**保持空间:**默认的 sed 是不会操作保持空间的,保持空间是专门为用户提供的空间,这几个命令可以操作保持空间,来实现更复杂的功能。
**h:**把模式空间内容覆盖到保持空间中 **H:**把模式空间内容追加到保持空间中 **g:**把保持空间内容覆盖到模式空间中 **G:**把保持空间内容追加到模式空间中 **x:**交换模式空间与保持空间的内容
模式空间命令
有了模式空间的概念后,可以重新理解一下前面 p、d、n 等命令的本质。
**p:**打印当前模式空间所有内容,追加到默认输出之后。
**P:**打印当前模式空间开端至\n的内容,并追加到默认输出之前。Sed并不对每行末尾\n进行处理,但是对N命令追加的行间\n进行处理,因为此时sed将两行看做一行。
**n:**命令简单来说就是提前读取下一行,覆盖模型空间前一行,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed。
**N:**命令简单来说就是追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有\n换行符,然后执行后续命令。然后再读取新行,对新读取的内容重头执行sed。此时,新读取的行会覆盖之前的行(之前的两行已经合并为一行)。
**d:**命令是删除当前模式空间内容(不再传至标准输出), 并放弃之后的命令,并对新读取的内容,重头执行sed。
**D:**命令是删除当前模式空间开端至\n的内容(不在传至标准输出), 放弃之后的命令,但是对剩余模式空间重新执行sed。
操作脚本中的范围指定
sed命令可以不带地址范围指定,在这种情况下,将对所有输入行执行该命令。
,
——范围分隔符+
——到接下来几行,~
——行数倍数匹配,到第一次倍数匹配的位置~
——步进$
——最后一行!
——范围取反/[正则匹配式]/
——正则表达式范围
运行
$ for a in $(seq 1 1 6);do echo modao$a;done > a.txt
$ cat a.txt
modao1
modao2
modao3
modao4
modao5
modao6
$ ls
a.txt
$ cat a.txt
modao1
modao2
modao3
modao4
modao5
modao6
$ sed '1,3a newmodao' a.txt
modao1
newmodao
modao2
newmodao
modao3
newmodao
modao4
modao5
modao6
$ sed '1,3i newmodao' a.txt
newmodao
modao1
newmodao
modao2
newmodao
modao3
modao4
modao5
modao6
$ sed '1,3c newmodao' a.txt
newmodao
modao4
modao5
modao6
$ sed '1,3d' a.txt
modao4
modao5
modao6
$ sed '1,3p' a.txt
modao1
modao1
modao2
modao2
modao3
modao3
modao4
modao5
modao6
$ sed -n '1,3p' a.txt
modao1
modao2
modao3
$ sed -n '1,3=' a.txt
1
2
3
$ sed '1,3=' a.txt
1
modao1
2
modao2
3
modao3
modao4
modao5
modao6
$ sed '1,3s/modao/regex/' a.txt
regex1
regex2
regex3
modao4
modao5
modao6
$ sed -n '1,3s/modao/regex/' a.txt
$ sed '1,3y/modao/regex/' a.txt
regee1
regee2
regee3
modao4
modao5
modao6
$ sed -n '1,3{y/modao/regex/;p}' a.txt
regee1
regee2
regee3
$ sed -n '1,3{y/modao/regex/;p}' a.txt > b.txt
$ cat b.txt
regee1
regee2
regee3
$ sed -n '3,$rb.txt' a.txt
regee1
regee2
regee3
regee1
regee2
regee3
regee1
regee2
regee3
regee1
regee2
regee3
$ sed '3rb.txt' a.txt
modao1
modao2
modao3
regee1
regee2
regee3
modao4
modao5
modao6
$ sed -n '3rb.txt' a.txt
regee1
regee2
regee3
$ sed '/modao4/bend;p;:end' a.txt
modao1
modao1
modao2
modao2
modao3
modao3
modao4
modao5
modao5
modao6
modao6
$ sed -n '/modao4/bend;p;:end' a.txt
modao1
modao2
modao3
modao5
modao6
$ sed -n '/modao4/p;tend;s/modao/modao233/;:end' a.txt
modao4
$ sed '/modao4/d;tend;s/modao/modao233/;:end' a.txt
modao2331
modao2332
modao2333
modao2335
modao2336
$ sed '1h;2H;3x;4H;5H;6G' a.txt
modao1
modao2
modao1
modao2
modao4
modao5
modao6
modao3
modao4
modao5
$ sed 'n;p' a.txt
modao1
modao2
modao2
modao3
modao4
modao4
modao5
modao6
modao6
$ sed -n 'n;p' a.txt
modao2
modao4
modao6
$ sed -n 'N;P' a.txt
modao1
modao3
modao5
$ sed -n '1,3p' a.txt
modao1
modao2
modao3
$ sed -n '1,+3p' a.txt
modao1
modao2
modao3
modao4
$ sed -n '1,~3p' a.txt
modao1
modao2
modao3
$ sed -n '1~3p' a.txt
modao1
modao4
$ sed -n '1,$p' a.txt
modao1
modao2
modao3
modao4
modao5
modao6
$ sed -n '3,$!p' a.txt
modao1
modao2